package mymgo

import (
	"fmt"
	"strconv"

	"lottery/conf"

	"github.com/astaxie/beego/logs"
	//"github.com/astaxie/beego"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

type AutoIncEntity struct {
	Id  string `bson:"_id"`
	Seq int64  `bson:"seq"`
}

type Field struct {
	Id         string
	Collection string
}

type MdbSession struct {
	autoIncr *AutoIncr
	session  *mgo.Session
	db       string
}

func (mdb *MdbSession) Session() *mgo.Session {
	return mdb.session.New()
}

var (
	AutoIncIdCollection = "amb_config"
	field               = &Field{
		Id:         "seq",
		Collection: "_id",
	}
)

func GetDb(cfg *conf.Db) *MdbSession {
	var url = generateUrl(cfg)

	session, err := mgo.Dial(url)

	if err != nil {
		logs.Warn("config==> %+v", cfg)
		panic(err.Error())
	}

	autoIncr, err := NewAutoIncr([]string{"gamedata", "game", "order"})
	if err != nil {
		panic(err.Error())
	}

	return &MdbSession{
		session:  session,
		autoIncr: autoIncr,
		db:       cfg.Db,
	}
}

func generateUrl(self *conf.Db) string {
	url := self.Host
	if self.User != "" && self.Passwd != "" {
		url = self.User + ":" + self.Passwd + "@" + url
	}
	if self.Port != 0 {
		url = url + ":" + strconv.Itoa(self.Port)
	}
	if self.Db != "" {
		url = url + "/" + self.Db
	}
	return url
}

func (mdb *MdbSession) AutoIncId(name string) (id int) {
	if mdb.autoIncr.Contain(name) {
		return mdb.autoIncr.Inc(name)
	}

	s := mdb.Session()
	id, err := autoIncr(s.DB(mdb.db).C(AutoIncIdCollection), name)
	s.Close()
	if err != nil {
		panic("Get next id of [" + name + "] fail:" + err.Error())
	}
	return
}

func autoIncr(c *mgo.Collection, name string) (id int, err error) {
	return incr(c, name, 1)
}

func incr(c *mgo.Collection, name string, step int) (id int, err error) {
	result := make(map[string]interface{})
	change := mgo.Change{
		Update:    bson.M{"$inc": bson.M{field.Id: step}},
		Upsert:    true,
		ReturnNew: true,
	}
	_, err = c.Find(bson.M{field.Collection: name}).Apply(change, result)
	if err != nil {
		return
	}
	id, ok := result[field.Id].(int)
	if ok {
		return
	}
	id64, ok := result[field.Id].(int64)
	if !ok {
		err = fmt.Errorf("%s is ont int or int64", field.Id)
		return
	}
	id = int(id64)
	return
}
